package com.example.minibom.service;
import com.example.minibom.exception.ExistingException; // 使用新的异常类
import com.example.minibom.feign.BOMLinkFeign;
import com.example.minibom.feign.PartFeign;
import com.huawei.innovation.rdm.coresdk.basic.dto.GenericLinkQueryDTO;
import com.huawei.innovation.rdm.coresdk.basic.enums.ConditionType;
import com.huawei.innovation.rdm.coresdk.basic.vo.QueryRequestVo;
import com.huawei.innovation.rdm.coresdk.basic.vo.RDMParamVO;
import com.huawei.innovation.rdm.coresdk.basic.vo.RDMResultVO;
import com.huawei.innovation.rdm.minibom.dto.relation.BOMLinkCreateDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;

@Service
public class BomLinkService {
    @Autowired
    private BOMLinkFeign bomLinkFeign;
    @Autowired
    private PartFeign partFeign;

    /**
     * 根据部件ID查找其主部件ID（Master Part ID）
     *
     * @param sourceId 要查询的部件ID（不能为null）
     * @return 主部件ID
     * @throws IndexOutOfBoundsException 如果未找到对应部件
     * @throws ClassCastException 如果服务返回的数据结构不符合预期
     *
     * 实现步骤：
     * 1. 构建查询参数，按ID精确匹配部件
     * 2. 调用PartFeign查询部件详情
     * 3. 从返回结果中提取master对象的ID字段
     * 4. 将ID转换为Long类型返回
     */
    public Long findMasterId(Long sourceId) {
        // 1. 构建查询参数
        RDMParamVO<QueryRequestVo> paramWrapper = new RDMParamVO<>();
        QueryRequestVo queryParams = new QueryRequestVo();
        paramWrapper.setParams(queryParams);
        queryParams.addCondition("id", ConditionType.EQUAL, sourceId);

        // 2. 调用Feign客户端查询部件
        RDMResultVO partResult = partFeign.find("Part", paramWrapper);

        // 3. 解析返回数据（假设至少有一条记录）
        LinkedHashMap<String, Object> partData = (LinkedHashMap<String, Object>) partResult.getData().get(0);
        LinkedHashMap<String, Object> masterData = (LinkedHashMap<String, Object>) partData.get("master");

        // 4. 转换并返回ID
        return Long.parseLong((String) masterData.get("id"));
    }

    /**
     * 查询目标部件的直接父部件（通过BOMLink关联）
     *
     * @param targetId 目标部件ID（作为关联关系中的Target端）
     * @return 包含父部件列表的RDMResultVO
     *
     * 实现逻辑：
     * 1. 构建关联关系查询参数，设置：
     *    - objectId: 目标部件ID
     *    - role: "Target"（表示查询指向该部件的关联）
     * 2. 调用BOMLinkFeign查询关联关系
     * 3. 返回原始查询结果（由调用方解析）
     */
    public RDMResultVO findParent(Long targetId) {
        GenericLinkQueryDTO linkQuery = new GenericLinkQueryDTO();
        linkQuery.setObjectId(targetId);
        linkQuery.setRole("Target"); // 关键参数：定义查询方向

        RDMParamVO<GenericLinkQueryDTO> paramWrapper = new RDMParamVO<>();
        paramWrapper.setParams(linkQuery);

        return bomLinkFeign.queryRelatedObjects("BOMLink", paramWrapper);
    }

    /**
     * 精确查找特定Source和Target的BOMLink记录
     *
     * @param sourceId 源部件ID（BOMLink的Source端）
     * @param targetId 目标部件ID（BOMLink的Target端）
     * @return 匹配的BOMLink记录集合（可能为空）
     *
     * 技术细节：
     * - 使用复合条件查询：同时匹配source.id和target.id
     * - 返回值中的data字段为List<BOMLink>
     */
    public RDMResultVO findBomLink(Long sourceId, Long targetId) {
        QueryRequestVo queryParams = new QueryRequestVo();
        queryParams.addCondition("source.id", ConditionType.EQUAL, sourceId); // 关键条件1
        queryParams.addCondition("target.id", ConditionType.EQUAL, targetId); // 关键条件2

        RDMParamVO<QueryRequestVo> paramWrapper = new RDMParamVO<>();
        paramWrapper.setParams(queryParams);

        return bomLinkFeign.find("BOMLink", paramWrapper);
    }

    /**
     * 创建BOMLink关联关系（含业务规则校验）
     *
     * @param link 包含source和target的DTO
     * @return 创建成功的BOMLink对象
     * @throws ExistingException 违反以下规则时抛出：
     *     1. 禁止将部件作为自己的子项（targetId == masterId）
     *     2. 禁止重复创建已存在的BOMLink
     *     3. 禁止循环引用（target是source的祖先节点）
     *
     * 实现流程：
     * 1. 获取source部件的masterId
     * 2. 校验规则1：禁止自引用
     * 3. 校验规则2：禁止重复关联
     * 4. 校验规则3：递归检查父级是否形成循环
     * 5. 通过所有校验后创建BOMLink
     */
    public Object create(BOMLinkCreateDTO link) {
        // 1. 提取ID
        Long sourceId = link.getSource().getId();
        Long targetId = link.getTarget().getId();
        Long masterId = findMasterId(sourceId);

        // 2. 规则1：禁止自引用
        if (targetId.equals(masterId)) {
            throw new ExistingException("部件不能作为自己的子项");
        }

        // 3. 规则2：检查是否已存在相同关联
        if (!findBomLink(sourceId, targetId).getData().isEmpty()) {
            throw new ExistingException("该BOMLink关联已存在");
        }

        // 4. 规则3：递归检查循环引用
        RDMResultVO parentResult = findParent(masterId);
        while (!parentResult.getData().isEmpty()) {
            LinkedHashMap<String, Object> parentLink = (LinkedHashMap<String, Object>) parentResult.getData().get(0);
            Long parentMasterId = Long.parseLong((String) ((LinkedHashMap<?, ?>) parentLink.get("master")).get("id"));

            if (parentMasterId.equals(targetId)) {
                throw new ExistingException("禁止循环引用：目标部件是源部件的祖先");
            }

            parentResult = findParent(parentMasterId); // 继续向上查找
        }

        // 5. 创建关联
        RDMParamVO<BOMLinkCreateDTO> createParam = new RDMParamVO<>();
        createParam.setParams(link);
        return bomLinkFeign.create("BOMLink", createParam).getData().get(0);
    }

    //找到所有没有父节点的项
    /**
     * 查找所有没有父部件的顶级部件（用于构建BOM树的根节点）
     *
     * @return 结构：
     * {
     *   "result": "SUCCESS",
     *   "data": List<Part> （已去重）
     * }
     *
     * 核心逻辑：
     * 1. 查询所有BOMLink记录
     * 2. 提取每条记录的source部件
     * 3. 检查该部件是否有父级关联
     * 4. 若无父级且未重复，加入结果集
     */
    public RDMResultVO findAllSourcePart() {
        // 1. 查询所有BOMLink
        RDMResultVO allLinks = bomLinkFeign.find("BOMLink", new RDMParamVO<>());

        // 2. 去重处理
        HashSet<Long> masterIdSet = new HashSet<>();
        List<Object> topLevelParts = new ArrayList<>();

        for (Object linkObj : allLinks.getData()) {
            LinkedHashMap<String, Object> bomLink = (LinkedHashMap<String, Object>) linkObj;
            LinkedHashMap<String, Object> sourcePart = (LinkedHashMap<String, Object>) bomLink.get("source");
            Long masterId = Long.parseLong((String) ((LinkedHashMap<?, ?>) sourcePart.get("master")).get("id"));

            // 3. 检查是否为顶级部件
            if (findParent(masterId).getData().isEmpty() && !masterIdSet.contains(masterId)) {
                masterIdSet.add(masterId);
                topLevelParts.add(sourcePart);
            }
        }

        // 4. 包装结果
        RDMResultVO result = new RDMResultVO();
        result.setData(topLevelParts);
        result.setResult("SUCCESS");
        return result;
    }
}
